package cn.iocoder.yudao.module.erp.service.purchaseorder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.purchaseorder.vo.PurchaseOrderPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.purchaseorder.vo.PurchaseOrderSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchaseorder.PurchaseOrderDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchaseorder.PurchaseOrderGoodsDO;
import cn.iocoder.yudao.module.erp.dal.mysql.purchaseorder.PurchaseOrderGoodsMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.purchaseorder.PurchaseOrderMapper;
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PURCHASE_ORDER_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PURCHASE_ORDER_NO_EXISTS;

/**
 * 采购订单 Service 实现类
 *
 * @author maxuxu
 */
@Service
@Validated
@Slf4j
public class PurchaseOrderServiceImpl implements PurchaseOrderService {

    @Resource
    private PurchaseOrderMapper purchaseOrderMapper;
    @Resource
    private PurchaseOrderGoodsMapper purchaseOrderGoodsMapper;
    @Resource
    private ErpNoRedisDAO erpNoRedisDAO;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPurchaseOrder(PurchaseOrderSaveReqVO createReqVO) {
        // 插入
        PurchaseOrderDO purchaseOrder = BeanUtils.toBean(createReqVO, PurchaseOrderDO.class);
        if (ObjUtil.isEmpty(purchaseOrder.getBillNo())) {
            String no = erpNoRedisDAO.generate(ErpNoRedisDAO.PURCHASE_ORDER_NO_PREFIX);
            validExistNo(no);
            purchaseOrder.setBillNo(no);
        }
        purchaseOrderMapper.insert(purchaseOrder);
        // 插入子表
        createPurchaseOrderGoodsList(purchaseOrder.getId(), createReqVO.getPurchaseOrderGoodss());
        // 返回
        return purchaseOrder.getId();
    }

    private void validExistNo(String no) {
        PurchaseOrderDO purchaseOrderDO = purchaseOrderMapper.selectByNo(no);
        if (ObjUtil.isNotEmpty(purchaseOrderDO)) {
            throw exception(PURCHASE_ORDER_NO_EXISTS);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePurchaseOrder(PurchaseOrderSaveReqVO updateReqVO) {
        // 校验存在
        validatePurchaseOrderExists(updateReqVO.getId());
        // 更新
        PurchaseOrderDO updateObj = BeanUtils.toBean(updateReqVO, PurchaseOrderDO.class);
        purchaseOrderMapper.updateById(updateObj);

        // 更新子表
        updatePurchaseOrderGoodsList(updateReqVO.getId(), updateReqVO.getPurchaseOrderGoodss());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePurchaseOrder(Long id) {
        // 校验存在
        validatePurchaseOrderExists(id);
        // 删除
        purchaseOrderMapper.deleteById(id);

        // 删除子表
        deletePurchaseOrderGoodsByOrderId(id);
    }

    @Override
    public void deleteAnyPurchaseOrder(Collection<Long> ids) {
        purchaseOrderMapper.deleteBatchIds(ids);
    }

    private void validatePurchaseOrderExists(Long id) {
        if (purchaseOrderMapper.selectById(id) == null) {
            throw exception(PURCHASE_ORDER_NOT_EXISTS);
        }
    }

    @Override
    public PurchaseOrderDO getPurchaseOrder(Long id) {
        return purchaseOrderMapper.selectById(id);
    }

    @Override
    public PageResult<PurchaseOrderDO> getPurchaseOrderPage(PurchaseOrderPageReqVO pageReqVO) {
        return purchaseOrderMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（采购单和物品的链接表-多对多关系） ====================

    @Override
    public List<PurchaseOrderGoodsDO> getPurchaseOrderGoodsListByOrderId(Long orderId) {
        return purchaseOrderGoodsMapper.selectListByOrderId(orderId);
    }

    @Override
    public BigDecimal getSumSaleOrderAmount() {
        PurchaseOrderDO sumSaleOrderAmount = purchaseOrderMapper.getSumOrderAmount();
        return sumSaleOrderAmount.getTotalAmount();
    }

    @Override
    public BigDecimal getSumSaleOrderAmountBySyncPay(Integer syncPay) {
        PurchaseOrderDO sumSaleOrderAmount = purchaseOrderMapper.getSumOrderAmountBySyncPay(syncPay);
        return sumSaleOrderAmount.getTotalAmount();
    }

    private void createPurchaseOrderGoodsList(Long orderId, List<PurchaseOrderGoodsDO> list) {
        list.forEach(o -> o.setOrderId(orderId).setId(null).setNoInNum(o.getNumber()));
        purchaseOrderGoodsMapper.insertBatch(list);
    }

    private void updatePurchaseOrderGoodsList(Long orderId, List<PurchaseOrderGoodsDO> list) {
//        deletePurchaseOrderGoodsByOrderId(orderId);
//		list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
//        createPurchaseOrderGoodsList(orderId, list);
        List<PurchaseOrderGoodsDO> oldList = purchaseOrderGoodsMapper.selectListByOrderId(orderId);
        List<List<PurchaseOrderGoodsDO>> lists = CollectionUtils.diffList(oldList, list, (oldItem, newItem) -> oldItem.getId().equals(newItem.getId()));
        if (CollUtil.isNotEmpty(lists.get(0))) {
            lists.get(0).forEach(item -> {
                item.setOrderId(orderId);
            });
            purchaseOrderGoodsMapper.insertBatch(lists.get(0));
        }
        if (CollUtil.isNotEmpty(lists.get(1))) {
            purchaseOrderGoodsMapper.updateBatch(lists.get(1));
        }
        if (CollUtil.isNotEmpty(lists.get(2))) {
            purchaseOrderGoodsMapper.deleteBatchIds(convertList(lists.get(2), PurchaseOrderGoodsDO::getId));
        }
    }

    private void deletePurchaseOrderGoodsByOrderId(Long orderId) {
        purchaseOrderGoodsMapper.deleteByOrderId(orderId);
    }

}